#include <iostream>
#include "Poco/ThreadPool.h"
#include "Poco/Exception.h"
#include "ThreadPool.h"

using namespace SystemTool;

namespace SystemTool
{
    class InnerTarget : public Poco::Runnable
    {
    public:
        void SetFunc(std::function<void(void *)> fFunc, void *pUserData)
        {
            m_fFunc = fFunc;
            m_pUserData = pUserData;
        }

        virtual void run()
        {
            if (m_fFunc)
            {
                m_fFunc(m_pUserData);
            }
            // Destroy this obj
            delete this;
        }

    private:
        std::function<void(void *)> m_fFunc = nullptr;
        void *m_pUserData = nullptr;
    };
}

// Construct the pool
ThreadPool::ThreadPool(int iPoolSize) : m_iPoolSize(iPoolSize)
{
    m_pThreadPool = new Poco::ThreadPool(2, iPoolSize);

}

// Destruct the pool
ThreadPool::~ThreadPool()
{
    if(m_pThreadPool)
    {
        delete (Poco::ThreadPool*)m_pThreadPool;
        m_pThreadPool = nullptr;
    }
}

// Start to get a thread to excute task
void ThreadPool::Start(std::function<void(void*)> fFunc, void *pUserData,  TDPriority ePreority)
{
    if (m_pThreadPool)
    {
        InnerTarget *pTarget = new InnerTarget;
        pTarget->SetFunc(fFunc, pUserData);

        try
        {
            ((Poco::ThreadPool *)m_pThreadPool)->startWithPriority((Poco::Thread::Priority)(int)ePreority, *pTarget);
        }
        catch (const Poco::Exception &e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
            if (pTarget)
            {
                delete pTarget;
                pTarget = nullptr;
            }
        }
    }
}

// Join all
void ThreadPool::JoinAll()
{
    if (m_pThreadPool)
    {
        try
        {
            ((Poco::ThreadPool *)m_pThreadPool)->joinAll();
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Stop all
void ThreadPool::StopAll()
{
    if (m_pThreadPool)
    {
        try
        {
            ((Poco::ThreadPool *)m_pThreadPool)->stopAll();
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Get current pool capacity
int ThreadPool::GetCurCapacity() const
{
    if (m_pThreadPool)
    {
        return ((Poco::ThreadPool *)m_pThreadPool)->capacity();
    }

    return 0;
}

// Expand poll
void ThreadPool::ExpandCapacity(int iThreadCnt)
{
    if (m_pThreadPool)
    {
        try
        {
            ((Poco::ThreadPool *)m_pThreadPool)->addCapacity(iThreadCnt);
        }
        catch(const Poco::Exception& e)
        {
            std::cerr << "Err happened:" << e.displayText() << std::endl;
        }
    }
}

// Get current available threads
int ThreadPool::GetCurAvailable() const
{
    if (m_pThreadPool)
    {
        return ((Poco::ThreadPool *)m_pThreadPool)->available();
    }

    return 0;
}
